package edu.hcmus.sow.web.task;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import javax.mail.MessagingException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import edu.hcmus.sow.dao.TaskCommentDAO;
import edu.hcmus.sow.dao.TaskDAO;
import edu.hcmus.sow.dao.TaskStatusDAO;
import edu.hcmus.sow.dao.TaskWorkLogDAO;
import edu.hcmus.sow.dao.UserDAO;
import edu.hcmus.sow.domain.Project;
import edu.hcmus.sow.domain.Task;
import edu.hcmus.sow.domain.TaskAttachment;
import edu.hcmus.sow.domain.TaskCategory;
import edu.hcmus.sow.domain.TaskComment;
import edu.hcmus.sow.domain.TaskStatus;
import edu.hcmus.sow.domain.TaskWorkLog;
import edu.hcmus.sow.domain.User;
import edu.hcmus.sow.domain.repository.FileInfo;
import edu.hcmus.sow.service.RepositoryService;
import edu.hcmus.sow.service.TaskService;
import edu.hcmus.sow.service.UserService;
import edu.hcmus.sow.utils.SecurityUtil;
import edu.hcmus.sow.utils.StringUtil;

@Controller
public class TaskController {

   @Autowired
   TaskService taskService;

   @Autowired
   TaskDAO taskDAO;

   @Autowired
   TaskStatusDAO taskStatusDAO;

   @Autowired
   UserDAO userDAO;

   @Autowired
   TaskCommentDAO taskCommentDAO;

   @Autowired
   TaskWorkLogDAO taskWorkLogDAO;

   @Autowired
   RepositoryService repositoryService;
   
   @Autowired
   UserService userService;
   
   // ---------------------------------------------------------------------------------------------------------------
   // TASK
   // ---------------------------------------------------------------------------------------------------------------

   @RequestMapping("/project/{id}")
   public ModelAndView task( @PathVariable("id") Integer projectID ) {

      ModelAndView mav = new ModelAndView();
      
      mav.addObject("projectID", projectID);

      // Get Tasks List beside a ProJectID
      List<Task> taskList = taskService.getByProjectID(projectID);
      mav.addObject("tasks", taskList);

      // get number comment of each task
      List<Integer> numberComments = taskService.getNumberCommentOfEachTask(taskList);
      mav.addObject("comments", numberComments);

      // get UserList
      List<User> userList = userDAO.findAll();
      mav.addObject("userlists", userList);

      // get Categories
      List<TaskCategory> categories = taskService.getCategories();
      mav.addObject("categories", categories);

      // get Projects
      List<Project> projects = taskService.getProjects();
      mav.addObject("projects", projects);

      mav.setViewName("task");

      return mav;
   }

   

   @RequestMapping("/task/{id}/view")
   public ModelAndView viewTask(@PathVariable Integer id) {
      ModelAndView mav = new ModelAndView();

      // get Current task
      Task task = taskService.findByID(id);
      mav.addObject("task", task);

      //get task attachment files
      List<TaskAttachment> attachments = taskService.getTaskAttacments(id);
      mav.addObject("attachments", attachments);
      
      // load comment...
      List<TaskComment> taskCommentsList = taskService.getTaskCommentList(id);
      mav.addObject("commentLists", taskCommentsList);

      // get UserList
      List<User> userList = userDAO.findAll();
      mav.addObject("userlists", userList);

      // get TaskWorkLog list
      List<TaskWorkLog> workLogList = taskService.getTaskWorkLogLists(id);
      mav.addObject("workLogLists", workLogList);

      // get Categories
      List<TaskCategory> categories = taskService.getCategories();
      mav.addObject("categories", categories);

      // get Projects
      List<Project> projects = taskService.getProjects();
      mav.addObject("projects", projects);

      mav.setViewName("taskdetail");

      mav.addObject("taskID", id);
      return mav;
   }

   @RequestMapping(value = "/task/{id}/delete", method = RequestMethod.GET)
   public String deleteTask(@PathVariable Integer id, @RequestParam("projectID") Integer projectID) {
      taskService.deleteTask(id);
      return "redirect:/project/" + projectID;
   }

   @RequestMapping("/ajax/task/{id}/update")
   @ResponseBody
   public ModelAndView updateTask(@PathVariable("id") Integer id, @RequestParam("title") String title,
         @RequestParam("description") String description, @RequestParam("assignedTo") Integer assignID,
         @RequestParam("project") Integer projectID, @RequestParam("category") Integer categoryID,
         @RequestParam("dueDate") String dueDate, @RequestParam("estHours") String estHours,
         @RequestParam("remindWhen") String remindWhen, @RequestParam("isSendMail") String isSendMail
         ){
      ModelAndView mav = new ModelAndView();
      taskService.updateTask(id, title, description, assignID, categoryID, projectID, estHours, dueDate);
      
      /*//Send email notify to assigned user
      if (isSendMail.equals("true")){
         // get logged in user
         int userID = SecurityUtil.getCurrentLoggedinUserID();
         User user = userService.getUserByID(userID);
         // Init user ID list to get email list
         List<Integer> userIDs = new ArrayList<Integer>();
         // add User need to send email
         userIDs.add(assignID);
         if (userIDs.size() > 0) {
            List<String> receiverList = new ArrayList<String>();
            // get email list
            receiverList = taskService.getEmailByUserID(userIDs);
            String fromEmail = "nsbloc@gmail.com";
            String emailTitle = "[SOW]";
            String emailContent = user.getUsername() + " have been edited the task :\n" + title;
            emailContent += "\n Description:" + description;
            try {
               if(receiverList.size() > 0)
                  MailProcess.sendSSLMail(fromEmail, receiverList, emailTitle, emailContent);
            } catch (MessagingException e) {
               // TODO Auto-generated catch block
               e.printStackTrace();
            }
         }
      }*/
      // get Current task
      Task task = taskService.findByID(id);
      mav.addObject("task", task);

      //get task attachment files
      List<TaskAttachment> attachments = taskService.getTaskAttacments(id);
      mav.addObject("attachments", attachments);
      
      // load comment...
      List<TaskComment> taskCommentsList = taskService.getTaskCommentList(id);
      mav.addObject("commentLists", taskCommentsList);

      // get UserList
      List<User> userList = userDAO.findAll();
      mav.addObject("userlists", userList);

      // get TaskWorkLog list
      List<TaskWorkLog> workLogList = taskService.getTaskWorkLogLists(id);
      mav.addObject("workLogLists", workLogList);

      // get Categories
      List<TaskCategory> categories = taskService.getCategories();
      mav.addObject("categories", categories);

      // get Projects
      List<Project> projects = taskService.getProjects();
      mav.addObject("projects", projects);

      mav.addObject("taskID", id);
      mav.setViewName("controls/c_taskContents");
      
      return mav;
   }

   @RequestMapping(value = "/ajax/viewTask", method = RequestMethod.POST)
   public ModelAndView ajaxLoadTasks(@RequestParam("projectID") Integer projectID, @RequestParam("time") Integer time) {
      ModelAndView mav = new ModelAndView();
      // get TaskList
      List<Task> taskList = taskService.getCompletedTaskListByProject(projectID, time);
      mav.addObject("completeTasks", taskList);

      // get number comment of each task
      List<Integer> numberComments = taskService.getNumberCommentOfEachTask(taskList);
      mav.addObject("commentsCompleted", numberComments);

      mav.setViewName("controls/c_completedTask");
      
      return mav;
   }

   // Add Task
   @RequestMapping(value = "/ajax/task/addQuick", method = RequestMethod.POST)
   public ModelAndView addTask(@RequestParam("projectID") Integer projectID, @RequestParam("taskName") String title,
         @RequestParam("assignedTo") Integer assignedTo) {
      ModelAndView mav = new ModelAndView();

      taskService.createTask(projectID, title, "This has been created", assignedTo, null, null, null, null);

      // Get Tasks List beside a ProJectID
      List<Task> taskList = taskService.getByProjectID(projectID);
      mav.addObject("tasks", taskList);
      mav.setViewName("controls/c_tasksList");

      return mav;
   }

   @RequestMapping("/ajax/task/add")
   public ModelAndView addTask(@RequestParam("projectID") Integer projectID, @RequestParam("title") String title,
         @RequestParam("description") String description,@RequestParam("assignedTo") Integer assignTo,
         @RequestParam("project") Integer project, @RequestParam("category") Integer categoryID,
         @RequestParam("dueDate") String dueDate, @RequestParam("estHours") String estHours,
         HttpServletRequest request) {

      ModelAndView mav = new ModelAndView();
      // Add task
      taskService.createTask(projectID, title, description, assignTo, project, categoryID, dueDate, estHours);

      // Get Tasks List beside a ProJectID
      List<Task> taskList = taskService.getByProjectID(projectID);
      mav.addObject("tasks", taskList);

      // get number comment of each task
      List<Integer> numberComments = taskService.getNumberCommentOfEachTask(taskList);
      mav.addObject("comments", numberComments);

      mav.setViewName("controls/c_tasksList");
      return mav;
   }
   
   @RequestMapping("/ajax/task/sendMail") //to one
   public void sendMail ( 
         @RequestParam("title") String title,
         @RequestParam("description") String description,
         @RequestParam("assignedTo") Integer assignTo){
      
      // get logged in user
      int userID = SecurityUtil.getCurrentLoggedinUserID();
      User user = userService.getUserByID(userID);
      // Init user ID list to get email list
      List<Integer> userIDs = new ArrayList<Integer>();
      // add User need to send email
      userIDs.add(assignTo);
      if (userIDs.size() > 0) {
         // Send mail
         List<String> receiverList = new ArrayList<String>();
         // get email list
         receiverList = taskService.getEmailByUserID(userIDs);
         String fromEmail = "nsbloc@gmail.com";
         String emailTitle = "[SOW]";
         String emailContent = user.getUsername() + " have been created the task :\n" + title;
         emailContent += "\n Description:" + description;
         try {
            if(receiverList.size() > 0)
               MailProcess.sendSSLMail(fromEmail, receiverList, emailTitle, emailContent);
         } catch (MessagingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
         }
      }
   }
   
   @RequestMapping("/ajax/task/sendMailToUsers") //to many
   public void sendMailToMany ( 
         @RequestParam("taskID") Integer taskID,
         @RequestParam("content") String content,
         @RequestParam("userList") String userList){
      
      // get logged in user
      int userID = SecurityUtil.getCurrentLoggedinUserID();
      User user = userService.getUserByID(userID);
      // get user list to send email...
      List<Integer> userIDs = new ArrayList<Integer>();
      if (userList != "") {
         String[] users = userList.split(";");
         if (!users[0].equals("0")){ // check the first is all email?
            for (int i = 0; i < users.length; i++) {
               userIDs.add(Integer.parseInt(users[i]));
            }
         }
         else{
            for (int i = 1; i < users.length; i++) {
               userIDs.add(Integer.parseInt(users[i]));
            }
         }
         List<String> receiverList = new ArrayList<String>();
         receiverList = taskService.getEmailByUserID(userIDs);

         String fromEmail = "nsbloc@gmail.com";
         String emailTitle = "[SOW]";
         String emailContent = user.getUsername() + " have been commented on this task \n" + taskDAO.findByID(taskID).getTitle();
         emailContent += "\n Content" + content;

         // Send mail to User list.
         try {
            if(receiverList.size() > 0)
               MailProcess.sendSSLMail(fromEmail, receiverList, emailTitle, emailContent);
         } catch (MessagingException e) {
            e.printStackTrace();
         }
      }
   }
   // ---------------------------------------------------------------------------------------------------------------
   // TASK DETAILS
   // ---------------------------------------------------------------------------------------------------------------

   // Change adjusted estimate when user pull the scroll bar
   @RequestMapping(value = "/ajax/updateEstimate", method = RequestMethod.POST)
   public ModelAndView ajaxUpdateAdjustEstimate(@RequestParam("taskID") Integer id,
         @RequestParam("progress") Integer progress) {
      ModelAndView mav = new ModelAndView();

      taskService.updateProgressOfTask(id, progress);
      mav.addObject("adjustedEstimate", progress);
      // mav.setViewName("taskdetail");

      // get Current task
      Task task = taskService.findByID(id);
      mav.addObject("task", task);

      // load comment...
      List<TaskComment> taskCommentsList = taskService.getTaskCommentList(id);
      mav.addObject("commentLists", taskCommentsList);

      // get UserList
      List<User> userList = userDAO.findAll();
      mav.addObject("userlists", userList);

      // get TaskWorkLog list
      List<TaskWorkLog> workLogList = taskService.getTaskWorkLogLists(id);
      mav.addObject("workLogLists", workLogList);

      // get Categories
      List<TaskCategory> categories = taskService.getCategories();
      mav.addObject("categories", categories);

      // get Projects
      List<Project> projects = taskService.getProjects();
      mav.addObject("projects", projects);

      mav.setViewName("taskdetail");

      mav.addObject("taskID", id);

      return mav;
   }

   // Mark completed task
   @RequestMapping(value = "/task/{id}/markCompleted", method = RequestMethod.GET)
   public ModelAndView markCompletedTask(@PathVariable("id") Integer taskID, @RequestParam("project") Integer projectID) {
      ModelAndView mav = new ModelAndView();

      Task task = taskDAO.findByID(taskID);
      if (task != null) {
         taskService.markComplete(taskID, projectID);
         mav.addObject("projectID", projectID);
         
         // Get Tasks List beside a ProJectID
         List<Task> taskList = taskService.getByProjectID(projectID);
         mav.addObject("tasks", taskList);

         // get UserList
         List<User> userList = userDAO.findAll();
         mav.addObject("userlists", userList);

         // get Categories
         List<TaskCategory> categories = taskService.getCategories();
         mav.addObject("categories", categories);

         // get Projects
         List<Project> projects = taskService.getProjects();
         mav.addObject("projects", projects);

         // set Task has been marked as completed.
         mav.addObject("completedTaskID", task.getId());
         mav.addObject("completedTaskTitle", task.getTitle());
         
         mav.setViewName("task");
      }
      return mav;
   }

   @RequestMapping(value = "/ajax/markCompletedTask", method = RequestMethod.POST)
   public ModelAndView ajaxMarkCompletedTask(@RequestParam("taskID") Integer taskID) {
      ModelAndView mav = new ModelAndView();

      // get Task Completed Status
      TaskStatus taskStt = taskStatusDAO.findById(1);

      // get Task
      Task task = taskDAO.findByID(taskID);

      // set Status
      task.setTaskStatus(taskStt);

      // set progress of task
      task.setAdjustedEstimate(100);

      // update task
      task = taskService.saveTask(task);

      mav.setViewName("taskdetail");

      return mav;
   }

   // add new comment for task
   @RequestMapping(value = "/ajax/task/addComment", method = RequestMethod.POST)
   public ModelAndView ajaxAddComment(
         @RequestParam("taskID") Integer taskID,
         @RequestParam("content") String content) {
      ModelAndView mav = new ModelAndView();
      taskService.addComment(taskID, content);
      // load comment...
      List<TaskComment> taskCommentsList = taskService.getTaskCommentList(taskID);
      mav.addObject("commentLists", taskCommentsList);
      mav.setViewName("controls/c_taskCommentList");
      return mav;
   }

   // Delete a task comment
   @RequestMapping("/task/comment/{id}/delete")
   public String deleteComment(@PathVariable("id") Integer id) {

      TaskComment taskComment = taskCommentDAO.findByID(id);
      Integer taskID = taskComment.getTask().getId();
      taskService.deleteComment(id);

      String redirect = "redirect:/task/" + taskID + "/view";
      return redirect;
   }

   // Update comment
   @RequestMapping(value = "/task/{taskID}/comment/{commentID}/update", method = RequestMethod.GET)
   public String updateComment(@PathVariable("commentID") Integer commentID, @PathVariable("taskID") Integer taskID,
         @RequestParam("comment") String content) {

      // update comment content of task
      TaskComment taskComment = taskCommentDAO.findByID(commentID);

      if (taskComment != null) {
         taskComment.setContent(content);
         taskCommentDAO.merge(taskComment);
      }

      String redirectString = "redirect:/task/" + taskID + "/view";
      return redirectString;
   }

   // ---------------------------------------------------------------------------------------------------------------
   // TASK WORK LOG
   // ---------------------------------------------------------------------------------------------------------------

   // Add new time spent
   @RequestMapping(value = "/ajax/addTimeSpent", method = RequestMethod.POST)
   public ModelAndView ajaxAddTimeSpent(@RequestParam("taskID") Integer taskID,
         @RequestParam("loggedDate") String loggedDate, @RequestParam("person") Integer person,
         @RequestParam("timeSpent") String stringTimeSpent, @RequestParam("note") String note) {
      ModelAndView mav = new ModelAndView();

      Integer timeSpent = StringUtil.convertTimeSpentToInt(stringTimeSpent);

      taskService.addTaskWorkLog(taskID, loggedDate, person, timeSpent, note);

      // get TaskWorkLog list
      List<TaskWorkLog> workLogList = taskService.getTaskWorkLogLists(taskID);
      mav.addObject("workLogLists", workLogList);
      mav.addObject("taskID", taskID);
      mav.setViewName("controls/c_workLogLists");
      return mav;
   }

   // delete Task Work Log
   @RequestMapping(value = "task/{taskID}/timespent/delete", method = RequestMethod.GET)
   public String deleteTaskWorkLog(@PathVariable("taskID") Integer taskID, @RequestParam("id") Integer spentID) {

      TaskWorkLog twl = taskWorkLogDAO.findById(spentID);
      if (twl != null) {
         taskService.deleteTaskWorkLog(spentID);
      }

      String redirect = "redirect:/task/" + taskID + "/view";
      return redirect;
   }

   // ---------------------------------------------------------------------------------------------------------------
   // TASK CATEGORIES
   // ---------------------------------------------------------------------------------------------------------------

   @RequestMapping("/taskCategories")
   public ModelAndView EditCategories() {
      ModelAndView mav = new ModelAndView();

      mav.setViewName("editCategories");
      List<TaskCategory> categories = taskService.getCategories();
      mav.addObject("categories", categories);

      return mav;
   }

   @RequestMapping(value = "/ajax/taskCategory/add", method = RequestMethod.POST)
   public ModelAndView addCategory(@RequestParam("title") String title, @RequestParam("description") String description) {
      ModelAndView mav = new ModelAndView();
      taskService.addCategories(title, description);
      mav.setViewName("controls/c_categories");
      List<TaskCategory> categories = taskService.getCategories();
      mav.addObject("categories", categories);
      return mav;
   }

   @RequestMapping(value = "/ajax/taskCategory/update", method = RequestMethod.POST)
   public ModelAndView updateCategory(@RequestParam("id") Integer id, @RequestParam("title") String title,
         @RequestParam("description") String description) {
      ModelAndView mav = new ModelAndView();
      System.out.println(123);
      taskService.updateTaskCategory(id, title, description);
      mav.setViewName("controls/c_categories");

      List<TaskCategory> categories = taskService.getCategories();
      mav.addObject("categories", categories);

      System.out.println(456);
      return mav;
   }

   @RequestMapping("/taskCategory/{id}/remove")
   public String deleteCategory(@PathVariable("id") Integer id) {

      taskService.deleteCategory(id);
      return "redirect:/taskCategories";
   }

   /*
    * //
    * ------------------------------------------------------------------------
    * --------------------------------------- // TASK CATEGORIES //
    * --------------
    * --------------------------------------------------------------
    * -----------------------------------
    * 
    * @RequestMapping("/ajax/task")
    * 
    * @ResponseBody public List<User> getUsersJson() { List<User> list =
    * userDAO.findAll();
    * 
    * return list; }
    */
   @RequestMapping(value = "/ajax/task/categories")
   @ResponseBody
   public List<TaskCategory> getCategires() {
      List<TaskCategory> list = taskService.getCategories();
      return list;
   }

   @RequestMapping(value = "/ajax/task/projects")
   @ResponseBody
   public List<Project> getProjects() {
      List<Project> list = taskService.getProjects();
      return list;
   }
   
   
   // ---------------------------------------------------------------------------------------------------------------
   // TASK CATEGORIES
   // ---------------------------------------------------------------------------------------------------------------
   
   @RequestMapping(value = "/task/{id}/attachment/upload", method = RequestMethod.POST)
   public String uploadAttachment(@PathVariable("id") Integer taskID, HttpServletRequest request) {
      try {
         // Create a new file upload handler
         ServletFileUpload upload = new ServletFileUpload();

         // Parse the request
         FileItemIterator iter = upload.getItemIterator(request);
         while (iter.hasNext()) {
            FileItemStream item = iter.next();
            String name = item.getFieldName();
            InputStream stream = item.openStream();
            if (item.isFormField()) {
               // System.out.println("Form field " + name + " with value " +
               // Streams.asString(stream) + " detected.");
            } else {
               System.out.println("File field " + name + " with file name " + item.getName() + " detected.");

               // Process the input stream
               FileInfo fi = repositoryService.saveFile(stream);
               System.out.println(fi.getRowkey());

               String fileName = item.getName();

               // if file name exists
               if (taskService.findFileByName(fileName) != null) {
                  int index = StringUtils.lastIndexOf(fileName, '.');
                  String temp = fileName.substring(0, index) + "_" + System.currentTimeMillis()
                        + fileName.substring(index);
                  fileName = temp;
               }

               // save file in database
               //File file = new File();
               TaskAttachment taskAttachment = new TaskAttachment();
               Task task = taskService.findByID(taskID);
               taskAttachment.setTask(task);
               
               taskAttachment.setFileName(fileName);
               taskAttachment.setRowkey(fi.getRowkey());
               taskAttachment.setFileSize(fi.getSize());

               int userID = SecurityUtil.getCurrentLoggedinUserID();
               User user = userService.getUserByID(userID);
               
               taskAttachment.setUser(user);
               taskAttachment = taskService.saveTaskAttachment(taskAttachment);
            }
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
      
      return "redirect:/task/"+ taskID +"/view";
   }
   
   
   @RequestMapping("/task/attachment/{id}/download")
   public void download(@PathVariable("id") Integer id, @RequestParam("rk") String rk, HttpServletResponse response) {
      // get file by id
      TaskAttachment attachment = taskService.getTaskAttachmentByID(id);

      // if exist file
      if (attachment != null) {
         response.setContentType(attachment.getFileType());
         response.setContentLength((int) attachment.getFileSize().longValue());
         response.setHeader("Content-Disposition", "attachment;filename=\"" + attachment.getFileName() + "\"");

         try {
            repositoryService.readFile(attachment.getRowkey(), response.getOutputStream());
            response.flushBuffer();
         } catch (Exception e) {
            e.printStackTrace();
         }

      }
   }
   
   //reload attachment list ...
   @RequestMapping ("/ajax/task/{id}/attachment")
   public ModelAndView refreshAttachment (@PathVariable("id") Integer id){
      ModelAndView mav = new ModelAndView();
      //get task attachment files
      List<TaskAttachment> attachments = taskService.getTaskAttacments(id);
      Task task = taskService.findByID(id);
      mav.addObject("task", task);
      mav.addObject("attachments", attachments);
      mav.setViewName("controls/c_taskAttachments");
      return mav;
   }
   
   //delete attachment file
   @RequestMapping("task/{taskID}/attachment/{id}/delete")
   public String deleteAttachment (
         @PathVariable("taskID") Integer taskID, @PathVariable("id") Integer attachmentID, @RequestParam("rk") String rk){
      taskService.deleteTaskAttachment(attachmentID, rk);
      return "redirect:/task/"+taskID+"/view";
   }
}
